Skip to content

fix: add LAN disable and SD stream interface setup to StartSdCardLoggingAsync#153

Merged
tylerkron merged 3 commits intomainfrom
fix/sd-card-logging-spi-bus-setup
Mar 20, 2026
Merged

fix: add LAN disable and SD stream interface setup to StartSdCardLoggingAsync#153
tylerkron merged 3 commits intomainfrom
fix/sd-card-logging-spi-bus-setup

Conversation

@tylerkron
Copy link
Copy Markdown
Contributor

Summary

  • StartSdCardLoggingAsync now sends DisableNetworkLan and SetStreamInterface(SdCard) before enabling SD storage and starting streaming. SD card and LAN share the SPI bus on the hardware — without disabling LAN first, SD card logging silently produces no files.
  • StopSdCardLoggingAsync now restores the stream interface to USB (for USB connections) so subsequent non-SD operations work correctly.
  • Updates SD card operation tests to assert the new 6-command sequence.

Context

The desktop app had been working around this via its PrepareSdInterface() method, which sent these commands before calling Core. When using Core directly (e.g. via the CLI example app), SD card logging would appear to start/stop successfully but no files were written to the card.

Test plan

  • All 815 existing unit tests pass (net8.0)
  • Hardware test: --sd-log-start --sd-log-format csv via example CLI creates a file on the SD card
  • Hardware test: --sd-log-start --sd-log-format protobuf via example CLI creates a file on the SD card
  • Verify --sd-list shows the new files after logging

🤖 Generated with Claude Code

…ingAsync

SD card and LAN share the SPI bus on the hardware. StartSdCardLoggingAsync
was missing the DisableNetworkLan and SetStreamInterface(SdCard) commands
that the desktop app was sending via its PrepareSdInterface() workaround.
This caused SD card logging to silently produce no files when called from
Core alone (e.g. via the example CLI app).

StopSdCardLoggingAsync now also restores the stream interface to USB for
USB connections so subsequent non-SD operations work correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: a0fb8798807b
@tylerkron tylerkron requested a review from a team as a code owner March 20, 2026 19:00
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix SD card logging by disabling LAN and configuring stream interface

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Disable LAN and set stream interface to SD card before logging
• Restore stream interface to USB after SD card logging stops
• Update tests to verify new 6-command sequence instead of 4
Diagram
flowchart LR
  A["StartSdCardLoggingAsync"] --> B["DisableNetworkLan"]
  B --> C["EnableStorageSd"]
  C --> D["SetStreamInterface SdCard"]
  D --> E["SetSdLoggingFileName"]
  E --> F["SetStreamFormat"]
  F --> G["StartStreamData"]
  H["StopSdCardLoggingAsync"] --> I["StopStreaming"]
  I --> J["DisableStorageSd"]
  J --> K["SetStreamInterface USB"]
Loading

Grey Divider

File Changes

1. src/Daqifi.Core/Device/DaqifiStreamingDevice.cs 🐞 Bug fix +15/-0

Add LAN disable and stream interface setup

• Added DisableNetworkLan command before enabling SD storage in StartSdCardLoggingAsync
• Added SetStreamInterface(StreamInterface.SdCard) command to route data stream to SD card
• Added SetStreamInterface(StreamInterface.Usb) restoration in StopSdCardLoggingAsync for USB
 connections
• Included 100ms delays after each new command for hardware synchronization

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs


2. src/Daqifi.Core.Tests/Device/SdCard/SdCardOperationsTests.cs 🧪 Tests +21/-15

Update SD card logging tests for new command sequence

• Updated StartSdCardLoggingAsync_SendsCorrectCommandSequence test to expect 6 commands instead of
 4
• Updated StartSdCardLoggingAsync_WithJsonFormat_SendsJsonFormatCommand test with new command
 sequence
• Updated StartSdCardLoggingAsync_WithCsvFormat_SendsCsvFormatCommand test with new command
 sequence
• Added assertions for DisableNetworkLan and SetStreamInterface commands in correct order

src/Daqifi.Core.Tests/Device/SdCard/SdCardOperationsTests.cs


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Mar 20, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. WiFi start drops connection🐞 Bug ✓ Correctness
Description
StartSdCardLoggingAsync unconditionally disables LAN, which is the communication interface for
WiFi/TCP-connected devices, so the active control connection can be cut before the remaining
SD/logging commands are applied. This can make SD logging start unreliable or fail entirely when
invoked over WiFi.
Code

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[R402-408]

+            // SD card and LAN share the SPI bus on the hardware, so LAN must be
+            // disabled before the SD card can be used.
+            Send(ScpiMessageProducer.DisableNetworkLan);
+            await Task.Delay(100, cancellationToken);
+
         Send(ScpiMessageProducer.EnableStorageSd);
         await Task.Delay(100, cancellationToken);
Evidence
WiFi devices connect via TcpStreamTransport, and the SD-vs-LAN SPI exclusivity is explicitly
documented: preparing SD requires disabling LAN, meaning LAN communication cannot be used
simultaneously. Since StartSdCardLoggingAsync now sends DisableNetworkLan without checking transport
type, calling it on a WiFi/TCP session will disable the very interface used to send subsequent
commands.

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[377-430]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[63-68]
src/Daqifi.Core/Device/Network/INetworkConfigurable.cs[44-60]
src/Daqifi.Core/Device/DaqifiDeviceFactory.cs[35-55]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`StartSdCardLoggingAsync` disables LAN unconditionally. On WiFi/TCP connections, LAN is the active control interface, so disabling it can sever the connection before the rest of the SD logging command sequence is executed.
### Issue Context
The codebase already distinguishes USB vs TCP via `IsUsbConnection`, and it already enforces USB-only behavior for SD card file downloads due to the SD/LAN SPI bus sharing.
### Fix Focus Areas
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[377-430]
### Suggested fix
- Add an early guard in `StartSdCardLoggingAsync`:
- If `!IsUsbConnection`, throw `InvalidOperationException` with a clear message (e.g., SD logging requires USB because SD and LAN share SPI bus).
- (Optional) Add/adjust unit tests to cover the `!IsUsbConnection` behavior using a non-serial transport test double.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. LAN not restored on stop 🐞 Bug ⛯ Reliability
Description
StopSdCardLoggingAsync disables SD storage but never re-enables LAN after StartSdCardLoggingAsync
disabled it, leaving the device in a LAN-disabled state after logging. This can break later network
operations unless callers know to manually call PrepareLanInterface.
Code

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[R448-456]

         StopStreaming();
         Send(ScpiMessageProducer.DisableStorageSd);
+            // Restore stream interface to USB so subsequent non-SD operations work.
+            if (IsUsbConnection)
+            {
+                Send(ScpiMessageProducer.SetStreamInterface(StreamInterface.Usb));
+            }
+
Evidence
The class provides a symmetric interface-switch API: PrepareSdInterface disables LAN and enables SD,
while PrepareLanInterface disables SD and enables LAN. Multiple SD operations explicitly restore LAN
in finally blocks, establishing that LAN restoration is expected after SD usage;
StopSdCardLoggingAsync currently does not perform the corresponding restoration.

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[257-285]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[294-353]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[582-662]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[439-460]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`StopSdCardLoggingAsync` does not restore the LAN interface after `StartSdCardLoggingAsync` disables it, leaving the device in a LAN-disabled state.
### Issue Context
The class already defines `PrepareLanInterface()` as the standard way to restore LAN (it disables SD storage and enables LAN). Other SD operations restore LAN in `finally` blocks.
### Fix Focus Areas
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[439-460]
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[272-285]
### Suggested fix
- In `StopSdCardLoggingAsync`, after `Send(DisableStorageSd)`, restore LAN using one of:
- Call `PrepareLanInterface()` (may resend DisableStorageSd but is idempotent), or
- Send `ScpiMessageProducer.EnableNetworkLan` explicitly.
- Consider adding a short settle delay (reuse `SD_INTERFACE_SETTLE_DELAY_MS`) if subsequent commands are likely to follow immediately.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Cancellation leaves LAN disabled 🐞 Bug ⛯ Reliability
Description
If cancellation occurs during the awaited delays in StartSdCardLoggingAsync after LAN is disabled
and/or the stream interface is switched, the method throws without cleanup and can leave the device
with LAN disabled and the stream interface pointing at SD. This leaves the device in an inconsistent
state compared to other SD operations that always restore LAN in a finally block.
Code

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[R404-413]

+            Send(ScpiMessageProducer.DisableNetworkLan);
+            await Task.Delay(100, cancellationToken);
+
         Send(ScpiMessageProducer.EnableStorageSd);
         await Task.Delay(100, cancellationToken);
+            // Route the data stream to the SD card interface.
+            Send(ScpiMessageProducer.SetStreamInterface(StreamInterface.SdCard));
+            await Task.Delay(100, cancellationToken);
+
Evidence
StartSdCardLoggingAsync uses await Task.Delay(..., cancellationToken) between interface-switch
commands, so cancellation can occur after partial state changes (e.g., LAN disabled). Other SD card
operations wrap SD interface switching in try/finally and call PrepareLanInterface to restore LAN
regardless of errors, but StartSdCardLoggingAsync does not.

src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[377-430]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[294-353]
src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[582-662]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`StartSdCardLoggingAsync` performs multiple stateful device commands separated by cancellable delays. If cancellation (or any exception) happens mid-sequence, the method exits without restoring LAN/stream interface, leaving the device misconfigured.
### Issue Context
Other SD card operations in this class use `try/finally` to restore the LAN interface (`PrepareLanInterface`) even if an error occurs.
### Fix Focus Areas
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[377-430]
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[272-285]
### Suggested fix
- Wrap the command sequence in `try { ... } catch { ... }` or `try/finally`.
- Track a `bool started` (or similar) that is set only after the full successful sequence (including `StartStreaming`) completes.
- In `finally`, if `!started` and the device is still connected, best-effort restore:
- Disable SD storage if it was enabled
- Re-enable LAN (`PrepareLanInterface` or `EnableNetworkLan`)
- Restore stream interface (e.g., to `Usb` when `IsUsbConnection`)
- Avoid throwing from cleanup: swallow restoration failures similarly to `DownloadSdCardFileAsync`’s best-effort restoration.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines 448 to +456
StopStreaming();
Send(ScpiMessageProducer.DisableStorageSd);

// Restore stream interface to USB so subsequent non-SD operations work.
if (IsUsbConnection)
{
Send(ScpiMessageProducer.SetStreamInterface(StreamInterface.Usb));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Lan not restored on stop 🐞 Bug ⛯ Reliability

StopSdCardLoggingAsync disables SD storage but never re-enables LAN after StartSdCardLoggingAsync
disabled it, leaving the device in a LAN-disabled state after logging. This can break later network
operations unless callers know to manually call PrepareLanInterface.
Agent Prompt
### Issue description
`StopSdCardLoggingAsync` does not restore the LAN interface after `StartSdCardLoggingAsync` disables it, leaving the device in a LAN-disabled state.

### Issue Context
The class already defines `PrepareLanInterface()` as the standard way to restore LAN (it disables SD storage and enables LAN). Other SD operations restore LAN in `finally` blocks.

### Fix Focus Areas
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[439-460]
- src/Daqifi.Core/Device/DaqifiStreamingDevice.cs[272-285]

### Suggested fix
- In `StopSdCardLoggingAsync`, after `Send(DisableStorageSd)`, restore LAN using one of:
  - Call `PrepareLanInterface()` (may resend DisableStorageSd but is idempotent), or
  - Send `ScpiMessageProducer.EnableNetworkLan` explicitly.
- Consider adding a short settle delay (reuse `SD_INTERFACE_SETTLE_DELAY_MS`) if subsequent commands are likely to follow immediately.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

tylerkron and others added 2 commits March 20, 2026 13:22
SD card logging requires USB because SD and LAN share the SPI bus.
Add an early guard that throws InvalidOperationException for non-USB
connections, matching the existing pattern in DownloadSdCardFileAsync.

Also fixes StopSdCardLoggingAsync test to expect the new
SetStreamInterface(Usb) restore command, and updates the download
non-USB test to use a dedicated TestableNonUsbStreamingDevice.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: a0fb8798807b
@tylerkron tylerkron merged commit 200a631 into main Mar 20, 2026
1 check passed
@tylerkron tylerkron deleted the fix/sd-card-logging-spi-bus-setup branch March 20, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant